0%

😄
😢

第一章 概述

一、计算机网络的概念

计算机网络概括为一个由通信子网和终端系统组成的通信系统。

二、计算机网络在逻辑上的组成及其各自的作用

  1. 计算机网络在逻辑上由终端系统和通信子网组成。

  2. ①终端系统:终端系统由计算机、终端控制器和计算机上所能提供共享的软件资源和数据源(如数据库和应用程序)构成。

​ ②终端系统的作用:负责信息的处理。

​ ③通信子网:通信子网是由用作信息交换的网络节点和通信线路组成的独立的数据通信系统。

​ ④通信子网的作用:承担全网的数据传输、转接、加工和变换等通信处理工作。

三、网络的类型(网络的拓扑结构、网络覆盖范围)

  1. 网络的拓扑结构(知道长什么样)

avatar

  • 星型结构
  • 树形结构
  • 总线型结构
  • 环形结构
  • 网络型结构
  1. 网络的覆盖范围
    • 有线网络
      • 个人区域网(Personal Area Network)
      • 局域网(Local Area Network)
      • 城域网(Metropolitan Area Network)
      • 广域网(Wide Area Network)
      • 因特网(Internet)
    • 无线网络
      • 无线个域网
      • 无线局域网
      • 无线城域网
      • 无线广域网

四、协议的概念和协议三要素的名称、含义

  1. 协议的概念:协议是指通信双方必须遵循的、控制信息交换的规则的集合,是一套语义和语法规则、用来规定有关功能部件在通信过程中的操作,他定义了数据发送和接受工作中必经的过程。
  2. 协议三要素
    • 语法:指数据与控制信息的结构或格式(怎么讲)
    • 语义:指对构成协议的协议元素含义的解释(讲什么)
    • 同步:规定了事件的执行顺序

五、网络体系结构的概念

计算机网络体系结构是计算机网络的分层及其服务和协议的集合。(体系结构是一个抽象的概念,它只从功能上描述计算机网络的结构,而不涉及每层的具体组成和实现细节)

六、OSI/RM体系结构

avatar

  1. 物理层:利用传输介质为通信的网络节点之间、维护和释放物理连接,实现比特流(bit)的透明传输,进而为数据链路层提供数据传输服务。(传输线路一般算第0层,物理层一般指接口)

  2. 数据链路层:在物理层提供服务的基础上,在通信的实体间建立数据链路连接,传输以(frame)为单位的数据包,并采用差错控制和流量控制的方法,使得有差错的物理线路变成无差错的数据链路。(网卡就工作在数据链路层,属于数据链路层设备)

  3. 网络层:为分组交换数据上的不同主机提供通信服务,为以分组为单位的数据包通过通信子网选择适当的路由并实现拥塞控制、网络互连等功能。

  4. 传输层:向用户提供端到端的数据传输服务,实现为上层屏蔽低层的数据传输问题。

  5. 会话层:负责维护通信中连个节点之间的会话连接的建立、维护和断开,以及数据的交换。

    表示层:用于处理在两个通信系统中交换信息的表示方式,主要包括数据格式变换、数据的加密与解密、数据的压缩和恢复等功能。(直接为应用层提供服务)

    应用层:为应用程序通过网络服务,它包含了各种用户使用的协议

avatar

​ 数据从封装再到解包的过程,H1~H7统称为报头

七、TCP/IP体系结构

avatar

avatar

IP over everything: IP通过网络接入层运行在不同物理网络之上。

Everything over IP: TCP/IP体系结构下,各种网络应用均是建立在IP基础之上。

第二章 数据通信技术基础

avatar

信息、信号、数据

一、数据通信系统计数指标的计算(传信率、传码率、信带宽度、时延、误码率、信道容量、香农公式、奈式第一准则)

  1. 数据传输速率:衡量数据通信系统能力的主要指标,主要包括传信速率和传码速率。

    • 传码速率:又称调制速率、波特率,记作$N_{Bd}$,是指在数据通信系统中,每秒钟传输信号码元的个数,单位是波特(Baud)。

    • 传信速率:又称比特率,记作$R_b$,是指在数据通信系统中,每秒传输二进制码元的个数,单位是比特/秒。

      若T为信号码元持续时间,传送M电平的信号,则:
      $$
      N_{Bd}=1/T\
      R_b=N_{Bd}log_2M
      $$

二、各种传输介质的名称

  • 有线传输介质(媒体)
    • 双绞线
    • 同轴电缆
    • 光缆
  • 无线传输介质
    • 无线电波(无线电波是一个广义的术语,从含义上,无线电波是全向传播,而微波则是定向传播)
    • 地面微波
    • 卫星微波
    • 红外线技术

实验要求

1、随机生成一个进程访问的逻辑页号列表,要求不少于100个页号,把这些页号存入文件page.txt。

2、编程分别实现FIFO、LRU和CLOCK算法,每次调用算法前要求用户输入页框数量,每种算法最后都需要给出页面的置换顺序以及缺页中断次数。

3、不断地改变页框数,完成这张曲线图,并且做出简短的小结,用于分析页框数对缺页率的影响。

程序最好能集成成一个,首先能分行输出显示随机生成的100个页号;然后让用户选择页框数,以页框数作为参数调用三个页面替换策略,记录、输出、比较它们的缺页中断次数、缺页中断率。结果不一定以曲线图形式显示,但要能保存在文件中并能在屏幕上以字符方式输出。

实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
#include <stdio.h> 
#include <stdlib.h>
#include <time.h>
#include <math.h>

int main(){
FILE *fp;
FILE *fp1;
FILE *fp2;
int request[100];
char input[100];
int i,j,s=0;
int page_table_count = 0;//记录文件中的页表数
int page_frame_count = 0;//页框数
int page_missing_count;//缺页数
float page_fault_rate;//缺页率
srand(time(NULL));//随机种子

fp = fopen('page.txt','w');
if (fp == NULL)
return -1;
fp2 = fopen('result.txt','a++');
//生成100个20以内的随机数
for (i=0;i<100;i++){
j = rand % 20;
fprintf(fp,"%d",j);
fprintf(fp2,"%d",j);
}
fclose(fp);
//fp1只读,fp只写
fp1 = fopen('page.txt','r');
if (fp1 == NULL)
return -1;
//读取page.txt中的请求队列
while(fscanf(fp1,'%d',&request[page_table_count]) != EOF){
page_table_count++;
printf('\n');
printf('================================================================================\n')
print("请求队列长度(页表数):%d\n",page_table_count);
for (i=0;i<page_table_count;i++){
print('%d',request[i]);//具体展示请求队列页表号顺序
}
print('\n');
printf('================================================================================\n')
print("请输入分配给进程的页框数:");
scanf("%d",&page_frame_count);
printf('\n');
printf("页框数:%d\n",page_frame_count);
printf('================================================================================\n')
//保存请求队列长度(页表数)和页框数到result.txt
fprintf(fp2,"页表数:%d\n",page_table_count);
fprintf(fp2,"页框数:%d\n",page_frame_count);

page_missing_count=FIFO(request,page_table_count,page_frame_count);
printf("FIFOFIFO:\n缺页数:%d\n",page_missing_count);
fprintf(fp2, "FIFO: %d \n", page_missing_count);
page_fault_rate = (float)page_missing_count/page_table_count;
printf("缺页率: %.2f\n", page_fault_rate);
fprintf(fp2, "缺页率: %.2f\n", page_fault_rate);
printf("==================================================================================\n");

page_missing_count =LRU(request,page_table_count,page_frame_count);
printf("LRU:\n缺页数:%d\n",page_missing_count);
fprintf(fp2, "LRU: %d \n", page_missing_count);
page_fault_rate = (float)page_missing_count/page_table_count;
printf("缺页率: %.2f\n", page_fault_rate);
fprintf(fp2, "缺页率: %.2f\n", page_fault_rate);
printf("==================================================================================\n");

page_missing_count =CLO(request,page_table_count,page_frame_count);
printf("CLOCK:\n缺页数:%d\n",page_missing_count);
fprintf(fp2, "CLOCK: %d \n", page_missing_count);
rate = (float)count/M;
page_fault_rate = (float)page_missing_count/page_table_count;
printf("缺页率: %.2f\n", page_fault_rate);
fprintf(fp2, "缺页率: %.2f\n", page_fault_rate);
printf("===================================================================================\n");
fprintf(fp2, "===================================================================================\n");

//关闭文件指针
fclose(fp1);
fclose(fp2);
return 0;
}
"""给数组赋值"""
void setarray(int arr[], int num, int val)
{
int i;

for (i = 0; i < num; i++)
arr[i] = val;
}
"""声明一个二维数组用来存储内存中页面变化情况"""
void initarr(int **arr, int rnum, int cnum)
{
int r, c;
for(r = 0; r < rnum; r++)
{
for(c = 0; c < cnum; c++)
arr[r][c] = -1;
}
}
"""查找内存 mem 中是否存在页面 page"""
int findexist(int mem[], int mnum, int page)
{
int i;

for (i = 0; i < mnum; i++){
if (mem[i] == page)
return i;
}

return -1;
}

"""查找内存 mem 中是否存空的位置"""
int findempty(int mem[], int mnum)
{
int i;

for (i = 0; i < mnum; i++){
if (mem[i] == -1)
return i;
}

return -1;
}

"""打印内存中页面的变化"""
void print(int **a, int rnum, int mnum){

int i = 0;
int k = 0;
int j;

while(i < mnum)
{
for(j = 10 * k; j < rnum; j++)
{
if(j != 10 * (k+1))
printf("%d\t", a[i][j]);

if(j % 10 == 0 && j != 10 * k && i == mnum-1)
{
i=-1;
k++;
printf("\n");
break;
}

if(j%10==0&&j!=k*10&&i!=mnum-1)
break;
}

printf("\n");
i++;

}
}

"""先进先出页面置换算法FIFO"""
int FIFO(int req[], int rnum, int mnum)
{
int c ount;
int i, j;
int pos;

/*分配内存空间,通常初始化为-1*/
int *mem = (int *)malloc(sizeof(int ) * mnum);
setarray(mem, mnum, -1);

/*time记录内存中每个页面进入的时间*/
int *time = (int *)malloc(sizeof(int) * mnum);
setarray(time, mnum, rnum);

/*a记录内存中存放的页面*/
int **a;
a = (int **)malloc(sizeof(int *) * mnum);
a[0] = (int *)malloc(sizeof(int) * rnum * mnum);
for(i = 1; i < mnum; i++)
a[i] = a[0] + i * rnum;
initarr(a, mnum, rnum);

/*缺页次数初始时为 0*/
count = 0;

for (i = 0; i < rnum; i++){

/*发现页面请求是否存在内存中*/
pos = findexist(mem, mnum, req[i]);

/*如果内存中存在页面请求*/
if (pos != -1){

for(j = 0; j < mnum; j++){
a[j][i+1] = a[j][i];
}
/*
a[0][i+1] = a[0][i];
a[1][i+1] = a[1][i];
a[2][i+1] = a[2][i]; */

continue;
}

/*如果内存中不存在缺页次数加一*/
count++;

/*内存中是否存在空位置可以存放新页面*/
pos = findempty(mem, mnum);

/*存在空位置,直接存入新页面,不做置换*/
if (pos != -1){
mem[pos] = req[i];
time[pos] = i;

a[pos][i] = req[i];
for(j = 0; j < mnum; j++){
a[j][i+1] = a[j][i];
}
/* a[0][i+1] = a[0][i];
a[1][i+1] = a[1][i];
a[2][i+1] = a[2][i]; */

continue;
}

/*不存在空位置,寻找要置换的页面,fifo*/
pos = 0;

for (j = 1; j < mnum; j++){
if (time[j] < time[pos]){
pos = j;
}
}

mem[pos] = req[i];
time[pos] = i;
a[pos][i] = req[i];
if(i < rnum-1) //防止数组越界
{
for(j = 0; j < mnum; j++){
a[j][i+1] = a[j][i];
}
/* a[0][i+1] = a[0][i];
a[1][i+1] = a[1][i];
a[2][i+1] = a[2][i]; */
}
}

for(j = 1; j < mnum; j++){
a[j][0] = -1;
}

/*打印内存中页面的变化*/
print(a, rnum, mnum);

free(time); //释放内存空间
free(mem);
free(a);

return count; //返回缺页次数

}

1.reveal.js编写ppt播放页面

1.1 reveal.js

reveal.js是一个展示内容的框架,可以理解为WEB版的ppt。

  • 和传统的ppt相比,reveal.js的优势体现在:

    • UI风格简洁优美,对数学公式、代码、多媒体扩展支持

    • 制作灵活、不限应用,只需修改HTML文件

    • 丰富的特性,支持过渡动画、代码高亮、markdown语法等

    • 极度轻量,占用空间和内存小

1.2 reveal.js的使用

  • 链接reveal.js相关样式

    1
    2
    3
    4
    5
    6
    <link rel="stylesheet" href="{% static 'dist/reset.css' %}">
    <link rel="stylesheet" href="{% static 'dist/reveal.css' %}">
    <link rel="stylesheet" href="{% static 'dist/theme/black.css' %}">

    <!-- Theme used for syntax highlighted code -->
    <link rel="stylesheet" href="{% static 'plugin/highlight/monokai.css' %}">
  • 主体部分

    1
    2
    3
    4
    5
    6
    7
    8
    <div class="reveal">
    <div class="slides">
    <section>
    slide1
    </section>
    <section>
    slide2
    </section>

    一个section标签代表一张PPT页面

1.3 reveal.js的事件监听

搭建网站的初衷是为了获得用户的点击流行为日志数据,而在PPT播放页面的体现就是用户点击翻页,浏览器则向服务器发送httprequest请求,服务器接收请求,从而获得诸如请求人ip、path等并作为用户日志信息存储。

而revael.js的slidechanged事件可以很好的做到这一点:

1
2
3
Reveal.addEventListener( 'slidechanged', function( event ) {

});

2 配置django的session模块

在settings.py中添加:

1
2
3
# session 设置
SESSION_EXPIRE_AT_BROWSER_CLOSE = True # 是否关闭浏览器使得Session过期(默认False)
SESSION_SAVE_EVERY_REQUEST = True # 是否每次请求都保存Session,默认修改之后才保存(默认False)

其作用是已经登录的用户每次关闭浏览器后,再次进入网站,需要再次输入用户名和密码进行登录。

3 个人中心修改密码

  • view.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class UpdatePwdView(View):
    def post(self, request):
    modify_form = ModifyPwdForm(request.POST)
    if modify_form.is_valid():
    pwd1 = request.POST.get("password1", "")
    pwd2 = request.POST.get("password2", "")
    if pwd1 != pwd2:
    return HttpResponse('{"status":"fail","msg":"密码不一致"}', content_type='application/json')
    user = request.user
    user.password = make_password(pwd2)
    user.save()

    return HttpResponse('{"status":"success"}', content_type='application/json')
    else:
    return HttpResponse(json.dumps(modify_form.errors), content_type='application/json')
  • urls.py

    1
    path("update/pwd/", UpdatePwdView.as_view(),name='update_pwd'),
  • js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    $(function(){
    //个人资料修改密码
    $('#jsUserResetPwd').on('click', function(){
    Dml.fun.showDialog('#jsResetDialog', '#jsResetPwdTips');
    });

    $('#jsResetPwdBtn').click(function(){
    $.ajax({
    cache: false,
    type: "POST",
    dataType:'json',
    url:"/users/update/pwd/",
    data:$('#jsResetPwdForm').serialize(),
    async: true,
    success: function(data) {
    if(data.password1){
    Dml.fun.showValidateError($("#pwd"), data.password1);
    }else if(data.password2){
    Dml.fun.showValidateError($("#repwd"), data.password2);
    }else if(data.status == "success"){
    Dml.fun.showTipsDialog({
    title:'提交成功',
    h2:'修改密码成功,请重新登录!',
    });
    Dml.fun.winReload();
    }else if(data.msg){
    Dml.fun.showValidateError($("#pwd"), data.msg);
    Dml.fun.showValidateError($("#repwd"), data.msg);
    }
    }
    });
    });

4 自定义Middleware+logging配置日志模块

  • settings.py

    • MIDDLEWARE注册

      1
      2
      3
      4
      5
      6
      7
      MIDDLEWARE = [

      ...

      # 自定义
      'midlog.LogMiddleware.OpLog_Mid',
      ]
    • logging配置

      formatters、filters、handlers、loggers的配置

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      # 日志配置
      LOGGING = {
      'version': 1,
      'disable_existing_loggers': False, # 是否禁用日志器

      'formatters': {
      'verbose': {
      'format': '%(levelname)s %(message)s'
      },
      'simple': {
      'format': ' %(message)s'
      },
      },

      # 过滤器
      'filters': {
      'require_debug_true': {
      '()': 'django.utils.log.RequireDebugTrue', # 过滤掉调试信息'
      },
      'skip_static_requests': {
      '()': 'django.utils.log.CallbackFilter',
      'callback': 'skip_static_requests'
      },
      },
      # 处理错误信息的对象
      'handlers': {
      'console': {
      'level': 'INFO',
      'class': 'logging.handlers.RotatingFileHandler',
      'filename': os.path.join(LOG_DIR, 'Info'),
      'backupCount': 5,
      'encoding': 'utf-8',
      'formatter': 'verbose'
      },
      'file': {
      'level': 'WARNING', # 记录WARNING级别以上的报错信息
      'class': 'logging.handlers.RotatingFileHandler',
      'filename': os.path.join(LOG_DIR, 'Warning'),
      'backupCount': 5,
      'formatter': 'verbose'
      }

      },
      'loggers': {
      # 日志器名
      'ClickStream': {
      'handlers': ['console', 'file'],
      'level': 'INFO'
      },
      }
      }
  • Middleware

    从request中获得请求时间、请求IP、请求人、请求路径、请求方法和请求参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    logger = logging.getLogger('ClickStream')


    class OpLog_Mid(MiddlewareMixin):
    __exclude_urls = ['index/'] # 定义不需要记录日志的url名单

    def process_request(self, request):
    # 存放请求过来时的时间
    request.init_time = time.time()
    return None

    def process_response(self, request, response):
    # 请求时间
    re_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())

    # 请求IP
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
    # 如果有代理,获取真实IP
    re_ip = x_forwarded_for.split(",")[0]
    else:
    re_ip = request.META.get('REMOTE_ADDR')

    # 请求人
    re_user = request.user.username

    # 请求路径
    re_path = request.path
    # 请求方法
    re_method = request.method

    # 请求参数
    re_content = request.GET if re_method == 'GET' else request.POST
    if re_content:
    # 筛选空参数
    re_content = json.dumps(re_content)
    else:
    re_content = None

    message = '%s %s %s %s %s %s' % (re_time, re_ip, re_user, re_path, re_method, re_content)

    logger.info(message)

    return response

环境

  • BT-Panel 7.5.1
  • CentOS 7.9
  • Django 2
  • python 3.7.9

步骤

1. 登录宝塔面板

  • 服务器终端中获取面板首页地址、用户名、密码
    • 面板首页地址:sudo /etc/init.d/bt default | grep 外网面板地址
    • 用户名:sudo /etc/init.d/bt default | grep username
    • 密码:sudo /etc/init.d/bt default | grep password
    • 或者 sudo /etc/init.d/bt default

2.安装常用Web服务组件

  • 选择推荐的LNMP即可

3.安装MySQL数据库

  • 在左侧软件商店中找到MySQL进行安装,并运行MySQL服务

  • 更改mysqld root账户密码

    • 进入宝塔SSH终端

    • mysql - u - p 进入mysql

    • show databases; 查看数据库

    • use mysql; 切换到mysql数据库

    • update user set password=password("password") where user="root"; password即要设置的密码

    • flush privileges;

  • 新建数据库,存储网站数据

    • 进入宝塔SSH终端

    • mysql - u - p 进入mysql

    • create database django_website;

4.安装Python项目管理组件

  • 在软件商店中安装Python项目管理组件

  • 打开Python项目管理组件,在版本管理中安装Python版本。

    avatar

5.添加项目站点

  • 左侧网站,添加站点

avatar

6.上传项目文件

  • pip3 freeze > requirements.txt 在本地先生成依赖文件requirements.txt

  • 将项目文件打包成压缩包,注意不要将项目文件夹打包,只需打包项目文件夹内的文件

  • 在宝塔面板左侧文件中,来到路径/www/wwwroot/xxxxx下,xxxxx为项目文件夹名

    • 删除404.html和index.html两个文件

    • 点击上传,选择本地的压缩包开始上传

    • 上传完毕后解压

    • /www/wwwroot/xxxxx下创建添加uwsgi配置文件uwsgi.ini

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      [uwsgi]
      #使用 Nginx 连接时使用,Django程序所在服务器地址
      socket = 127.0.0.1:8000 #配置和nginx连接的socket连接
      # 直接做 Web 服务器使用,Django程序所在服务器地址
      # http=127.0.0.1:8000
      master = true #配置启动管理主进程
      processes = 1 #配置启动的进程数
      threads = 2 #配置每个进程的线程数
      chdir = /www/wwwroot/django.com #配置项目路径,项目的所在目录
      chmod-socket = 660
      vacuum = true
      master = true
      max-requests = 1000
      wsgi-file= /www/wwwroot/django.com/MxOnline/wsgi.py #配置wsgi接口模块文件路径,也就是wsgi.py这个文件所在的目录
      daemonize = /www/wwwroot/django.com/uwsgi.log #日志记录
  • 执行数据库迁移操作

    1
    2
    python manage.py makemigrations #生成迁移文件
    python manage.py migrate #执行迁移

7.修改网站配置

  • 左侧网站,点击网站名,在弹出的窗口中找到’配置文件’,输入如下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    location / {
    include uwsgi_params;
    uwsgi_pass 127.0.0.1:8000; #端口要和uwsgi里配置的一样
    uwsgi_param UWSGI_SCRIPT MxOnline.wsgi; #wsgi.py所在的目录名+.wsgi
    uwsgi_param UWSGI_CHDIR /www/wwwroot/www.django.com/; #项目路径
    }
    location /static/ {
    alias /www/wwwroot/www.django.com/static/; #静态资源路径
    }

    avatar

8.Python项目管理中添加项目

avatar

  • 使用Python项目管理插件新建项目成功之后,会自动在项目j源码目录里创建一个虚拟环境,虚拟环境目录一般都是以项目名_venv形式命名的。
  • 在命令行输入 source 项目路径/项目名_venv/bin/activate
  • 项目管理器默认使用pip安装项目根目录requirements.txt内的模块,如有其他模块需要安装请手动进入虚拟环境安装

9.收集静态文件

  • 在宝塔面板里,点击网站路径进入项目路径下,找到settins.py文件,末尾处添加静态资源收集路径

    1
    2
    #把APP静态资源收集到指定的目录下,这里我收集到static目录下
    STATIC_ROOT = os.path.join(BASE_DIR, 'static')
  • 之后在SSH终端进入项目虚拟环境

    1
    source /www/wwwroot/项目文件夹/项目名_venv/bin/activate
  • 收集静态文件

    1
    python manage.py collectstatic

settings.py数据库连接配置

1
2
3
4
5
6
7
8
9
10
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'Database name',
'USER': 'user',
'PASSWORD': 'password',
'HOST': 'xxxx',
'PORT': 'xxxx',
}
}

avatar

  • control + shift + enter

    • 万能键
  • control + P

    • 参数提示
  • shift+F6

    • 重构式重命名

创建一个Django项目

  • cd 对应的python虚拟环境文件夹

  • workon 虚拟环境

  • django-admin startproject 项目名

  • cd 项目名文件夹

  • 创建app

    • python manage.py startapp app名
    • 或 django-admin startapp app名

实现一个请求

  • 注册一个路由

    • 在urls中

      • url(参数1,视图函数)

        • 参数1:匹配规则 正则
        • 视图函数:对应views中的一个函数,注意不写函数的括号
  • 去views实现对应的视图函数

    • 第一个参数是request
    • 永远记得返回response

模板配置

  • 在App中进行模板配置

    • 需要在App的根目录创建templates文件夹即可
    • 如果想让代码自动提示,只需标记文件夹为模板文件夹
  • 在项目目录进行模板配置

    • 需要在项目目录创建templates文件夹并标记
    • 需要在settings中进行注册
  • 在开发中使用第二种

    • 模板可以继承,复用

路由配置

  • 项目如果逻辑过于复杂可以进行拆分
    • 拆分为多个App

    • 拆分多个urls

      • 在App中创建urls

        • urlpatterns = [] 路由规则列表
        • 在根urls中进行子路由的包含
      • 子路由使用

        • 跟路由规则 + 子路由规则

数据操作 增删改查

  • 存储

    • save()
  • 查询

    • 查所有 objects.all()
    • 查单个 objects.get(pk=xx)
  • 更新

    • 基于查询的
    • 查好的对象,修改属性,然后save()
  • 删除

    • 基于查询的
    • 调用delete()

Django shell

  • 集成了python环境的shell终端
  • 通常在终端中做一些调试

如何调试bug

  • 看日志

    • 先看第一条
    • 再看最后一条
  • 梳理思路

    • 程序在哪一个位置和预期出现偏差

关系型数据库表关系

  • 1:1 一对一
  • 1:M 一对多
  • M:N 多对多

app.py

1
2
3
4
5
6
7
8
9
10
11
12
import sys

from PyQt5 import sip
from PyQt5.QtWidgets import *
from runlogin import Login


if __name__ == '__main__':
app = QApplication(sys.argv)
login = Login()
login.show()
sys.exit(app.exec_())
阅读全文 »